<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    .cvs {
      border: 1px solid red;
    }
  </style>
</head>

<body>
  <img src="./cloth.png" alt="" width="100">
  <canvas id="app" class="cvs" width="500px" height="500px">您的浏览器版本过旧，请升级至最新版本</canvas>
  <script>
    function draw() {
      // https://blog.csdn.net/u012468376/article/details/73350998
      const canvas = document.querySelector('#app');
      let cvsCtx;
      if (canvas.getContext) {
        cvsCtx = canvas.getContext('2d');
      }

      //绘制线段
      // cvsCtx.beginPath();
      // cvsCtx.moveTo(50,50);
      // cvsCtx.lineTo(100,300);
      // cvsCtx.closePath();
      // cvsCtx.stroke();

      //绘制三角形
      // cvsCtx.beginPath();
      // cvsCtx.moveTo(50, 50);
      // cvsCtx.lineTo(100, 50);
      // cvsCtx.lineTo(100, 100);
      // cvsCtx.closePath();
      // cvsCtx.stroke();

      //填充三角形
      // cvsCtx.beginPath();
      // cvsCtx.moveTo(50, 50);
      // cvsCtx.lineTo(100, 50);
      // cvsCtx.lineTo(100, 100);
      // cvsCtx.closePath();
      // cvsCtx.fillStyle = 'rgb(200,0,0)';
      // cvsCtx.fill();

      //绘制圆弧 arc
      // cvsCtx.beginPath();
      // cvsCtx.arc(50, 50, 100, 0, Math.PI / 2, false);
      // cvsCtx.stroke();

      // cvsCtx.beginPath();
      // cvsCtx.arc(300, 100, 100, 0, Math.PI / 2, true);
      // cvsCtx.closePath();
      // cvsCtx.fill();

      // cvsCtx.beginPath();
      // cvsCtx.arc(200, 300, 50, 0, Math.PI / 2, false);
      // cvsCtx.fill();

      // cvsCtx.beginPath();
      // cvsCtx.arc(300, 300, 40, -Math.PI / 2,Math.PI / 2, false);
      // cvsCtx.fill();

      // 另一种方法绘制圆弧 arcTo
      // cvsCtx.beginPath();
      // cvsCtx.moveTo(50, 50);
      // cvsCtx.arcTo(200, 50, 200, 200, 100);
      // cvsCtx.lineTo(200, 200);
      // cvsCtx.arcTo(200, 300, 50, 300, 100);
      // cvsCtx.lineTo(50, 300);
      // cvsCtx.arcTo(20, 300, 20, 200, 20);
      // cvsCtx.lineTo(20, 100);
      // cvsCtx.arcTo(20, 50, 50, 50, 20);
      // cvsCtx.closePath();
      // cvsCtx.stroke();
      // cvsCtx.fill();

      //绘制两次贝塞尔曲线
      // cvsCtx.beginPath();
      // cvsCtx.moveTo(50, 100);
      // cvsCtx.quadraticCurveTo(100, 50, 200, 100);
      // cvsCtx.stroke();

      //绘制三次贝塞尔曲线
      // cvsCtx.beginPath();
      // cvsCtx.moveTo(50, 50);
      // cvsCtx.bezierCurveTo(100, 10, 200, 10, 200, 100);
      // cvsCtx.strokeStyle = 'rgb(255,0,0)';
      // cvsCtx.stroke();

      //绘制彩色方块
      // for (let i = 0; i < 6; i++) {
      //   for (let j = 0; j < 6; j++) {
      //     cvsCtx.fillStyle = `rgb(${Math.floor(255-42.5*i)},${Math.floor(255-42.5*j)},0)`;
      //     cvsCtx.fillRect(j * 50, i * 50, 50, 50);
      //   }
      // }

      //绘制彩色边框
      // for (let i = 0; i < 6; i++) {
      //   for (let j = 0; j < 6; j++) {
      //     cvsCtx.strokeStyle = `rgb(${Math.floor(255-42.5*i)},${Math.floor(255-42.5*j)},0)`;
      //     cvsCtx.strokeRect(j*50, i*50, 50, 50);
      //   }        
      // }

      //透明度，cvsCtx.globalAlpha = 0.2;需要写在最前面， globalAlpha 属性在需要绘制大量拥有相同透明度的图形时候相当高效。
      //不过，我认为使用rgba()设置透明度更加好一些。
      // cvsCtx.globalAlpha = 0.2;

      // cvsCtx.beginPath();
      // cvsCtx.moveTo(200, 200);
      // cvsCtx.lineTo(100, 50);
      // cvsCtx.lineTo(100, 100);
      // cvsCtx.closePath();
      // cvsCtx.fillStyle = 'rgb(200,0,0)';
      // cvsCtx.fill();

      // for (let i = 0; i < 6; i++) {
      //   for (let j = 0; j < 6; j++) {
      //     cvsCtx.fillStyle = `rgb(${Math.floor(255-42.5*i)},${Math.floor(255-42.5*j)},0)`;
      //     cvsCtx.fillRect(j * 50, i *
      //       50, 50, 50);
      //   }
      // }

      // lineWidth 线宽 。 
      // lineCap 线条末端样式
      //1、butt：线段末端以方形结束。2、round：线段末端以圆形结束。
      //3、square：线段末端以方形结束，但是增加了一个宽度和线段相同，高度是线段厚度一半的矩形区域。

      // lineJoin 同一个path内，设定线条与线条间接合处的样式。
      //1、round 通过填充一个额外的，圆心在相连部分末端的扇形，绘制拐角的形状。 圆角的半径是线段的宽度。
      //2、bevel 在相连部分的末端填充一个额外的以三角形为底的区域， 每个部分都有各自独立的矩形拐角。
      //3、miter 通过延伸相连部分的外边缘，使其相交于一点，形成一个额外的菱形区域。

      //虚线
      // cvsCtx.setLineDash([20], 5);
      // cvsCtx.lineDashOffset = 0; //设置虚线的偏移
      // cvsCtx.strokeRect(50, 50, 100, 100);

      //绘制文本
      // cvsCtx.font = 'italic small-caps bold 100px arial';
      // cvsCtx.fillStyle = 'rgb(200,0,0)';
      // cvsCtx.fillText('Hello', 10, 100);
      // cvsCtx.strokeStyle = 'rgb(200,0,0)';
      // cvsCtx.strokeText('Hello', 10, 100);


      //绘制图片
      // 考虑到图片是从网络加载，如果 drawImage 的时候图片还没有完全加载完成，则什么都不做，
      // 个别浏览器会抛异常。所以我们应该保证在 img 绘制完成之后再 drawImage。
      // const img = new Image();
      // img.src = "./cloth.png"
      // img.onload = function () {
      //   cvsCtx.drawImage(img, 10, 20);//坐标
      // }

      //绘制标签里的图片
      // 考虑到图片是从网络加载，如果 drawImage 的时候图片还没有完全加载完成，则什么都不做，
      // 个别浏览器会抛异常。所以我们应该保证在 img 绘制完成之后再 drawImage。
      // const img = document.querySelector('img');
      // img.onload = function () {
      //   cvsCtx.drawImage(img, 10, 20, 100, 50);
      // }

      //切片 chrome 无法测试出来
      // 考虑到图片是从网络加载，如果 drawImage 的时候图片还没有完全加载完成，则什么都不做，
      // 个别浏览器会抛异常。所以我们应该保证在 img 绘制完成之后再 drawImage。
      // const img = document.querySelector('img');
      // cvsCtx.drawImage(img, 33, 71, 104, 124, 21, 20, 87, 104);


      // 状态的保存和回复
      // save 和 restore 方法是用来保存和恢复 canvas 状态的，都没有参数。
      // ​ Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。
      // 关于 save()
      // Canvas状态存储在栈中，每当save()方法被调用后，当前的状态就被推送到栈中保存。一个绘画状态包括：
      // 当前应用的变形（即移动，旋转和缩放）
      // strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur,
      // shadowColor, globalCompositeOperation 的值
      // 当前的裁切路径（clipping path）
      // 可以调用任意多次 save方法。(类似数组的push())
      // 关于restore()

      // cvsCtx.fillRect(0, 0, 150, 150); // 使用默认设置绘制一个矩形
      // cvsCtx.save(); // 保存默认状态

      // cvsCtx.fillStyle = 'red' // 在原有配置基础上对颜色做改变
      // cvsCtx.fillRect(15, 15, 120, 120); // 使用新的设置绘制一个矩形

      // cvsCtx.save(); // 保存当前状态
      // cvsCtx.fillStyle = '#FFF' // 再次改变颜色配置
      // cvsCtx.fillRect(30, 30, 90, 90); // 使用新的配置绘制一个矩形

      // cvsCtx.restore(); // 重新加载之前的颜色状态
      // cvsCtx.fillRect(45, 45, 60, 60); // 使用上一次的配置绘制一个矩形

      // cvsCtx.restore(); // 加载默认颜色配置
      // cvsCtx.fillRect(60, 60, 30, 30); // 使用加载的配置绘制一个矩形


      // 坐标原点平移 坐标点平移最好配合 save restore
      // cvsCtx.save();
      // cvsCtx.translate(100, 100);
      // cvsCtx.strokeRect(10, 10, 50, 50);
      // cvsCtx.translate(100, 100);
      // cvsCtx.save();
      // cvsCtx.restore();
      // cvsCtx.strokeRect(10, 10, 50, 50);
      // cvsCtx.restore();
      // cvsCtx.strokeRect(10, 10, 50, 50);

      //旋转和放大
      // cvsCtx.save();
      // cvsCtx.translate(200, 200);
      // cvsCtx.rotate(45 * Math.PI / 180);
      // cvsCtx.scale(2, 2);
      // cvsCtx.fillStyle = 'rgb(100,0,100)';
      // cvsCtx.fillRect(10, 10, 100, 100);
      // cvsCtx.restore();
      // cvsCtx.fillStyle = 'rgb(255,0,0)';
      // cvsCtx.fillRect(10, 10, 100, 100);
    }
    draw();
  </script>
</body>

</html>